#pragma once

#include <iostream>
#include <string>
#include <cassert>
#include <functional>
#include "Epoll.hpp"
#include "Sock.hpp"
#include "Err.hpp"
#include "log.hpp"

static const int gport = 8888;

using func_t = std::function<std::string(std::string)>;

class EpollServer
{
public:
    static const int gnum = 64;
    EpollServer(func_t func, uint16_t port = gport) : _func(func), _port(port)
    {
    }
    ~EpollServer()
    {
        _listhensock.Close();
        _epoller.Close();
    }

    void InitServer()
    {
        _listhensock.Socket();
        _listhensock.Bind(_port);
        _listhensock.Listhen();
        _epoller.Create();
    }

    void start()
    {
        // 将_listhensock添加到epoll中
        bool r = _epoller.AddEvent(_listhensock.Fd(), EPOLLIN);
        assert(r);
        (void)r;

        int timeout = -1;
        while (true)
        {
            int n = _epoller.Wait(revs, gnum, timeout); // 获取就绪文件fd
            switch (n)
            {
            case 0:
                logmessage(DEBUG, "time out ...");
                break;
            case -1:
                logmessage(WARNING, "epoll_wait failed");
                break;
            default:
                logmessage(DEBUG, "有%d个事件就绪", n);
                HandlerEvent(n);
                break;
            }
        }
    }

    void HandlerEvent(int num)
    {
        for (int i = 0; i < num; i++)
        {
            int fd = revs[i].data.fd;
            uint32_t events = revs[i].events;

            if (events & EPOLLIN) // 读事件就绪
            {
                // 新连接到来
                if (fd == _listhensock.Fd())
                {
                    std::string clientip;
                    uint16_t clientport;
                    int sock = _listhensock.Accept(&clientip, &clientport);
                    if (sock < 0)
                        continue;
                    logmessage(DEBUG, "[%s][%d]已连接", clientip.c_str(), clientport);
                    // 将sock添加到epoll中
                    bool r = _epoller.AddEvent(sock, EPOLLIN);
                    assert(r);
                    (void)r;
                }
                // 新I事件
                else
                {
                    char request[1024];
                    ssize_t s = recv(fd, request, sizeof(request), 0);
                    if (s > 0)
                    {
                        request[s - 1] = '\0';
                        request[s - 2] = '\0';

                        // std::cout << "client# " << buffer << std::endl;

                        // // 将数据发送回去
                        // std::string echo = " [epoll server echo] ";
                        // echo += buffer;

                        // 业务处理
                        std::string response = _func(request);

                        send(fd, response.c_str(), response.size(), 0);
                    }
                    else
                    {
                        if (s == 0)
                        {
                            logmessage(INFO, "client quit...");
                        }
                        else
                        {
                            logmessage(WARNING, "recv error,client quit...");
                        }
                        // 先移除再关闭fd
                        _epoller.DelEvent(fd);
                        close(fd);
                    }
                }
            }
        }
    }

private:
    uint16_t _port;
    Sock _listhensock;
    Epoller _epoller;
    struct epoll_event revs[gnum];
    func_t _func;
};